package com.itheima.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.service.EmployeeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.nio.charset.StandardCharsets;
import java.security.DigestException;
import java.time.LocalDateTime;

/**
 * @author 程达
 * @PackageName:com.itheima.reggie.controller
 * @ClassName:EmployeeController
 * @Description:关于员工请求的控制器 里面定义 处理员工请求的处理器 (一个个方法).
 * 实现功能
 * 员工登录  登出  员工增删改查
 * @date 2022/5/22 15:01
 **/
@Slf4j//开启日志
@RestController // 支持restful风格 因为返回内容一般都是json
// @ResponseBody：响应的对象的设置为json格式放到响应体中
//  +@Controller结合: 我们是控制层代码属于web层 与前端交互
@RequestMapping("/employee")//类上的映射路径，用来分类的
@Api(tags = "员工表相关接口")
public class EmployeeController {

    // 加上 我们controller依赖对象  依赖service层对象
    @Autowired
    private EmployeeService employeeService;

    /*
       @RequestBody Employee employee 从请求体中解析json数据封装成对象
        @PostMapping("/login") 处理post请求的映射路径
        */
    //怎么写一个 登录处理器
    // 下面是处理登录业务的 处理器用户登录 用户根据账号密码登录后，返回用户账号信息
    @PostMapping("/login")//restful风格 保存  HttpServletRequest需要把参数存到域中
    @ApiOperation(value = "员工登录校验接口")
    public R<Employee> login(@RequestBody Employee employee, HttpServletRequest request) {
        log.info("[员工登录]:employee{}" + employee);

        //具体业务开发
        //通过service完成业务,业务的分析(根据产品原型和需求文档)
        //  切忌 用经验开发
        //1:拿到客户端密码,进行MD5加密处理.
        String password = employee.getPassword();
        //  password是原始密码 要进行MD5加密,怎么进行呢  面向对象语言
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        log.info("查看加密后的密码:" + password);
        //2:根据用户名去数据库查询用户信息.
        //创建查询条件对象
        //QueryWrapper 条件查询构造器对象  LambadQueryWrapper解除硬编码的查询对象 语法简单
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Employee::getUsername, employee.getUsername());//前面要查的表字段,后面是参数
        //2.0 这里根据username去数据库查有没有这个数据
        Employee emp = employeeService.getOne(queryWrapper);//根据条件查询一条信息，看看是不是要登陆的用户账号

        // 2.1 用户名不存在  没有必要校验   返回 失败结果
        if (emp == null) {
            return R.error("登录失败,用户名或密码错误");
        }
        // 2.2 如果用户名存在呢  继续校验
        //3: 用户名存在 校验 密码
        //  3.1  如果密码不正确   返回登录失败结果
        //加密后的 和查询到的 密码进行校验
        if (!emp.getPassword().equals(password)) {
            return R.error("登录失败,用户名或密码错误");
        }
        //  3.2  如果密码正确  继续校验
        //4: 校验 该用户的 状态
        if (emp.getStatus() == 0) {//账号被禁用
            return R.error("登录失败,账号已禁用");
        }
        // 4.1 是0 就返回失败结果
        //  4.2  是1  可以登录
        // 5: 可以登录,用户马上登陆了,为了方便登录后的操作
        // 建议 要求 把员工id存到session中 (减少频繁登录  保证一次会话中只用登录一次)
        // 通过参数位置 把 request要过来，存到session中
        request.getSession().setAttribute("employee", emp.getId());

        // 6:返回登录成功结果
        return R.success(emp);//这个密码是加密的 不怕有问题

    }


    //       return R.success(new Employee());
    //    return R.error("登录失败,请重新登录");

    //成功  return new Result(code,data,msg);
    // 失败  return new Result(code,msg);


    /**
     * 员工退出
     * 业务
     * 把存在session中的用户 状态删除
     */
    @PostMapping("/logout")
    @ApiOperation(value = "员工退出接口")
    public R<String> logout(HttpServletRequest request) {
        log.info("[员工退出登录]");
        //清理session中保存当前用户的数据
        request.getSession().removeAttribute("employee");

        return R.success("退出成功");
    }

    /**
     * 1.处理器 关于 新增员工
     */
    @PostMapping
    @ApiOperation(value = "新增员工接口")
    public R<String> save(@RequestBody Employee employee, HttpServletRequest request) {
        // 1:employee只有5个数据
        log.info("[新增:{}]", employee);
        //2:设置 md5 加密后的密码
        String password = DigestUtils.md5DigestAsHex("123456".getBytes());
        employee.setPassword(password);
        // 3 设置 创建和更新时间
        // 对第一创建来说 是不是创建和更新时间是一样的 都当前时间
//        employee.setCreateTime(LocalDateTime.now());//当前时间jdk8新方法
//        employee.setUpdateTime(LocalDateTime.now());
//        //4:当前第一次创建 创建人既是修改人
//        // 创建人id --肯定先登录了 --把id session域中
//        Long empId = (Long) request.getSession().getAttribute("employee");
//        // 存到 创建人和更新人
//        employee.setUpdateUser(empId);
//        employee.setCreateUser(empId);
        // 5: employee除了id都完整了  再进行添加
        //      try{
        employeeService.save(employee);
        //        }catch (Exception e){
        //            return R.error("犹豫您的操作不当,添加失败");
        //        }

        // 设置响应结果对象
        return R.success("新增成功");
    }


    /**
     * 2.员工信息分页条件查询
     * GET /employee/page?page=1&pageSize=10&name=jack
     *
     * @param page     当前页码
     * @param pageSize 每页显示条数
     * @param name     查询条件
     * @return
     */
    @GetMapping("/page")
    @ApiOperation(value = "员工分页查询接口")
    public R<Page> page(int page, int pageSize, String name) {
        log.info("[进行分页条件查询]");
        // 一会儿可以看我的日志 看一个神奇效果
        log.info("page={},pageSize={},name={}", page, pageSize, name);
        //page pageSize 跟分页有关系  name是条件
        //  封装到Page对象中      条件相关的封装到 wrapper中
        // 1:构建分页构造器
        Page pageInfo = new Page(page, pageSize);
        // 2:构建 条件构造器    构建 wrapper 添加 name
        //  name这个条件是以什么形式出现的?   可有可无
        LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper();//所以一定要写泛型，要不你咋知道里面啥属性
        //wrapper.like(Employee::getName,name);// like  name = '%name值%'
        // 有没有可能name是空?
        // 3:添加条件
        wrapper.like(StringUtils.isNotEmpty(name), Employee::getName, name);
        //         true  就拼接 like
        //  false 没值 就不拼接like语句
        /**  import org.apache.commons.lang.StringUtils;
         *               StringUtils.isNotEmpty(name) 判断是不是空的  不是空就拼接sql
         * // 条件分页查询
         * IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
         */
        //4: 执行分页查询操作
        employeeService.page(pageInfo, wrapper);
        //5:执行完了之后 数据在哪? 查询后的数据在哪里? pageInfo
        // 我们把 pageInfo给前端即可
        return R.success(pageInfo);

    }

    //3.根据id修改员工信息(包括编辑禁用启用状态)
    @PutMapping
    @ApiOperation(value = "修改员工信息接口")
    public R<String> update(HttpServletRequest request, @RequestBody Employee employee) {
        log.info(employee.toString());
        //查询测试一下当前请求响应是不是在一个线程上
        long id = Thread.currentThread().getId();
        log.info("Controller中update线程id为：{}",id);
        //  Long empId = (Long) request.getSession().getAttribute("employee");
        //  employee.setUpdateTime(LocalDateTime.now());
        //  employee.setUpdateUser(empId);
        employeeService.updateById(employee);
        log.info("员工信息修改成功" + employee);
        return R.success("员工信息修改成功");
    }

    //4.根据id查询，也就是编辑员工信息页面数据回显
    @GetMapping("/{id}")
    @ApiOperation(value = "根据id查询员工接口")
    public R<Employee> getById(@PathVariable Long id) {
        log.info("根据id查询员工信息...");
        Employee employee = employeeService.getById(id);
        if (employee != null) {
            return R.success(employee);
        }
        return R.error("没有查询到对应员工信息");
    }
}
